package com.cqemme.activitiservice.listener;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.cqemme.activitiservice.po.AlarmMessageInfo;
import com.cqemme.activitiservice.utils.EmptyChecker;
import com.cqemme.activitiservice.utils.JedisUtil;
import com.cqemme.activitiservice.feign.SchoolServiceFeign;
import com.cqemme.activitiservice.feign.UserServiceFeign;
import com.cqemme.activitiservice.feign.WebsocketService;
import com.cqemme.comm.po.Result;
import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.UserTask;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.impl.persistence.entity.VariableInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.*;

/**
 * sos报警流程图监听器集合
 */
@Service("SosAlarmListener")
@Slf4j
public class SosAlarmListener {

    @Value("${node.api.getStudentAll}")
    private String getStudentAll;

    @Value("${node.api.getSosCandidate}")
    private String getSosCandidateUrl;

    @Value("${node.api.saveProcess}")
    private String saveProcessUrl;

    @Value("${node.api.saveProcessAtAssign}")
    private String saveProcessAtAssignUrl;

    @Value("${node.api.savaTissueLeader}")
    private String savaTissueLeaderUrl;

    @Resource
    private WebsocketService websocketService;

    @Resource
    private RuntimeService runtimeService;

    @Resource
    private UserServiceFeign userService;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private JedisUtil jedisUtil;

    @Resource
    private SchoolServiceFeign schoolServiceFeign;


    /**
     * 学生在校内报警所触发的自动任务 - 向老师/家长等组织推送报警信息
     * EnumSendMessageRole - 这个类是画流程图的时候所填入的组织约定类
     *
     * @param execution
     */
    public void sosNotify(DelegateExecution execution) {
        sosNotifyTransition(execution, "in");
    }

    /**
     * 学生在校外报警的消息推送服务任务
     *
     * @param execution
     */
    public void outerSosNotify(DelegateExecution execution) {
        sosNotifyTransition(execution, "out");
        return;
    }

    /**
     * 报警柱报警推送消息/火灾报警推送报警信息- 向保安/保安队长等组织推送报警信息
     *
     * @param execution
     */
    public void pillarNotify(DelegateExecution execution) {
        Map m = JSONObject.parseObject(JSONObject.toJSONString(execution.getCurrentFlowElement()), Map.class);
        //得到参数和值数组
        JSONArray field = (JSONArray) m.get("fieldExtensions");
        //要推送消息的组织
        String noticeTissue = null;
        for (int i = 0; i < field.size(); i++) {
            JSONObject jsonObj = field.getJSONObject(i);
            String fieldName = jsonObj.get("fieldName").toString();
            String stringValue = jsonObj.get("stringValue").toString();
            if ("noticeTissue".equals(fieldName)) {
                noticeTissue = stringValue;
            }
        }

        //组装推送报警信息
        AlarmMessageInfo alarmMessageInfo = new AlarmMessageInfo();
        Map<String, Object> extData = new HashMap<>();
        //要推送的组织/sos报警类型
        extData.put("tissue", noticeTissue);
        extData.put("alarmInfo", execution.getVariable("alarmInfo").toString());
        extData.put("instanceId", execution.getProcessInstanceId());
        //这里要约定报警柱是好多/火灾报警是好多
        alarmMessageInfo.setMessageType(10);
        alarmMessageInfo.setExtData(JSONObject.toJSONString(extData));
        //推给熊涛涛
        Result re = websocketService.receiveMessageInfo(JSONObject.toJSONString(alarmMessageInfo));

        //存节点描述
        String nodeKey = execution.getCurrentActivityId() + "_description";
        execution.setVariable(nodeKey, "已发送报警通知");

        return;
    }

    /**
     * sos推送报警消息给家长们的过渡函数
     *
     * @param execution
     * @param location
     */
    public void sosNotifyTransition(DelegateExecution execution, String location) {
        Map m = JSONObject.parseObject(JSONObject.toJSONString(execution.getCurrentFlowElement()), Map.class);
        //得到参数和值数组
        JSONArray field = (JSONArray) m.get("fieldExtensions");
        //要推送消息的组织
        String noticeTissue = null;
        for (int i = 0; i < field.size(); i++) {
            JSONObject jsonObj = field.getJSONObject(i);
            String fieldName = jsonObj.get("fieldName").toString();
            String stringValue = jsonObj.get("stringValue").toString();
            if ("noticeTissue".equals(fieldName)) {
                noticeTissue = stringValue;
            }
        }

        //校内还是校外报警
        String student = execution.getVariable("student").toString();
        Map<String, Object> stuMap = JSONObject.parseObject(student, Map.class);
        int msgType = 8;

        if("in".equals(stuMap.get("sosSite").toString())){
            String headerTeacherId="0";
            msgType=5;
            String studentId = ((Map) stuMap.get("Student")).get("id") + "";
            Result getTeacher=schoolServiceFeign.queryAllByEnumType(studentId);
            Object reData=getTeacher.getData();
            if(EmptyChecker.notEmpty(reData)){
                JSONArray teList=JSONArray.parseArray(reData.toString());
                headerTeacherId=teList.getJSONObject(0).get("tel")+"";
            }else{
                log.error("此学生：{} 无对应班主任信息，流程实例挂起",studentId);
            }
            //存班主任tel作为代理人
            execution.setVariable("headTeacher", headerTeacherId);
        }

        //组装推送报警信息
        AlarmMessageInfo alarmMessageInfo = new AlarmMessageInfo();
        Map<String, Object> extData = new HashMap<>();
        //要推送的组织/推送的学生/sos报警类型
        extData.put("tissue", noticeTissue);
        extData.put("student", student);
        extData.put("instanceId", execution.getProcessInstanceId());
        alarmMessageInfo.setMessageType(msgType);
        alarmMessageInfo.setExtData(JSONObject.toJSONString(extData));
        //推给熊涛涛
        Result re = websocketService.receiveMessageInfo(JSONObject.toJSONString(alarmMessageInfo));

        //存节点描述
        String nodeKey = execution.getCurrentActivityId() + "_description";
        execution.setVariable(nodeKey, "已发送报警通知");

        //存细节进mongo
        //saveInstanceToMongo(execution, student, noticeTissue, location);

        return;
    }

    /**
     * sos校徽报警保安自动到位处理流程图 - 保安到达报警地点任务
     * 安排哪些保安到报警地点
     */
    public void arrive(DelegateExecution execution) {

        String schoolId = execution.getVariable("schoolId").toString();
        String chartType = execution.getVariable("chartType").toString();
        Object alarmInfo = execution.getVariable("alarmInfo");

        //得到参数和值数组
        Map m = JSONObject.parseObject(JSONObject.toJSONString(execution.getCurrentActivitiListener()), Map.class);
        JSONArray field = (JSONArray) m.get("fieldExtensions");

        //得到完成此任务的组织/候选人人数
        String tissue = null;
        Integer candidateCount = 3;
        for (int i = 0; i < field.size(); i++) {
            //参数值是 - tissue
            String fieldName = field.getJSONObject(i).get("fieldName").toString();
            String stringValue = field.getJSONObject(i).get("stringValue").toString();
            if ("tissue".equals(fieldName)) {
                tissue = stringValue;
            }
            if ("candidateCount".equals(fieldName)) {
                try {
                    candidateCount = Integer.parseInt(stringValue);
                } catch (Exception e) {
                    log.error("学校：" + schoolId + " 流程图：sos-security" + "定义任务候选人格式有误", e);
                }
            }
        }
        //完成任务候选人组织数组
        String[] trsArr = tissue.split(",");

        Map<String, Object> param = new HashMap<>();
        param.put("schoolId", schoolId);
        param.put("trsArr", trsArr);
        param.put("chartType", chartType);
        param.put("candidateCount", candidateCount);
        if ("sos-security".equals(chartType)) {
            //得到离学生最近的数量候选人ids - node调用处得到
            String student = execution.getVariable("student").toString();
            Map<String, Object> studentMap = JSONObject.parseObject(student, Map.class);
            String studentId = ((Map) studentMap.get("Student")).get("id").toString();
            param.put("studentId", studentId);
        } else if ("pillar-alarm".equals(chartType) || "fire-alarm".equals(chartType)) {
            param.put("alarmInfo", alarmInfo);
        }

        Map<String, Object> nodeRe = restTemplate.postForObject(getSosCandidateUrl, param, Map.class);
        List<Map<String, Object>> candidateIds = (List<Map<String, Object>>) nodeRe.get("data");
        if (EmptyChecker.isEmpty(candidateIds)) {
            log.error("从node那边获取的某些组织的人员来前往报警处，但人员为空---组织：{}，学校id：{}", tissue, schoolId);
            return;
        }

        //动态添加此任务完成候选人
        FlowElement currentFlowElement = execution.getCurrentFlowElement();
        UserTask userTask = (UserTask) currentFlowElement;
        List<String> canIds = new ArrayList<>();
        //StringBuilder des = new StringBuilder();
        for (Map<String, Object> canOne : candidateIds) {
            canIds.add(canOne.get("id").toString());
            //des.append("、【" + canOne.get("name") + "-" + canOne.get("id") + "】");
        }
        userTask.setCandidateUsers(canIds);

        //存节点运行描述
//        execution.setVariable(
//                execution.getCurrentActivityId() + "_description",
//                "系统自动派遣报警点附近保安" + des.toString().substring(1) + "前往报警地点==="
//        );

        //保存流程细节
        saveInstanceToMongoAtAssign(execution, candidateIds, chartType, schoolId,alarmInfo);


        //我觉得这里需要再向具体的保安人员推送消息来通知他看手机app

        return;

    }

    /**
     * 拉取保安队长信息为其指定任务
     *
     * @param execution
     */
    public void leaderHandle(DelegateExecution execution) {
        //学校id
        String schoolId = execution.getVariable("schoolId").toString();
        //得到参数和值数组
        Map m = JSONObject.parseObject(JSONObject.toJSONString(execution.getCurrentActivitiListener()), Map.class);
        JSONArray field = (JSONArray) m.get("fieldExtensions");
        //得到组织
        String tissue = null;
        for (int i = 0; i < field.size(); i++) {
            //参数值是 - tissue
            String fieldName = field.getJSONObject(i).get("fieldName").toString();
            String stringValue = field.getJSONObject(i).get("stringValue").toString();
            if ("tissue".equals(fieldName)) {
                tissue = stringValue;
            }
        }

        //根据学校id和组织得到某些角色的人员
        Map<String, Object> map = new HashMap<>();
        map.put("orgId", Integer.parseInt(schoolId));
        map.put("roleList", new ArrayList<>(Arrays.asList(tissue.split(","))));
        Result rolesResult = userService.getRolesUser(map);
        List<Long> roleListold = (List) rolesResult.getData();
        if (EmptyChecker.isEmpty(roleListold)) {
            log.error("但查无对应组织的队长(如保安队长)，此流程实例被挂起。参数：{}，返回值：{}，流程实例id：{}", JSONObject.toJSONString(map), JSONObject.toJSONString(rolesResult), execution.getProcessInstanceId());
            return;
        }
        List<String> roleList = new ArrayList<>();
        for (Long rL : roleListold) {
            roleList.add(String.valueOf(rL));
        }
        FlowElement currentFlowElement = execution.getCurrentFlowElement();
        UserTask userTask = (UserTask) currentFlowElement;
        userTask.setCandidateUsers(roleList);

        //存细节数据
        //saveLeaderTaskToMongo(execution, roleList);
    }

    /**
     * 推送报警信息阶段保存sos报警细节进mongodb
     *
     * @param execution
     * @param student
     * @param noticeTissue
     */
    public void saveInstanceToMongo(DelegateExecution execution, String student, String noticeTissue, String location) {

        String instanceId = execution.getProcessInstanceId();
        String schoolId = execution.getVariable("schoolId").toString();

        //解析流程变量 student 字段
        List<Map<String, Object>> saveSosInfoList = new ArrayList<>();
        Map<String, Object> studentMap = JSONObject.parseObject(student, Map.class);
        String studentId = ((Map) studentMap.get("Student")).get("id").toString();
        Object distance = studentMap.get("distance");
        //根据学生信息在node取学生人物关系数据
        String url = getStudentAll + "?id=" + studentId;
        Result studentOth = restTemplate.getForObject(url, Result.class);
        Map<String, Object> studentRelationMap = (Map) studentOth.getData();
        List<Map<String, Object>> teacherList = (List) studentRelationMap.get("teacherList");
        List<Map<String, Object>> parentList = (List) studentRelationMap.get("parentList");

        //得到所有流程变量
        Map<String, VariableInstance> vars = runtimeService.getVariableInstances(instanceId);
        Map<String, Object> reVars = new HashMap<>();
        for (Map.Entry<String, VariableInstance> varOne : vars.entrySet()) {
            reVars.put(varOne.getKey(), varOne.getValue().getValue());
        }

        //记录推送消息组织阶段细节
        Map<String, String> instanceInfo = new HashMap<>();
        instanceInfo.put("noticeTissue", noticeTissue);

        //生成人物可追溯流程数据
        for (Map<String, Object> teaMap : teacherList) {
            Map<String, Object> sosMongo = new HashMap<>();
            sosMongo.put("schoolId", schoolId);
            sosMongo.put("peopleId", teaMap.get("tel"));
            sosMongo.put("name", teaMap.get("name"));
            sosMongo.put("peopleType", "teacher");
            sosMongo.put("processType", "sos-security");
            sosMongo.put("studentId", studentId);
            sosMongo.put("instanceId", instanceId);
            sosMongo.put("instanceInfo", instanceInfo);
            sosMongo.put("instanceVar", reVars);
            sosMongo.put("student", student);
            sosMongo.put("distance", distance);
            if ("out".equals(location)) {
                sosMongo.put("instanceYes", true);
                sosMongo.put("sosSite", "out");
            }
            saveSosInfoList.add(sosMongo);
        }
        for (Map<String, Object> parMap : parentList) {
            Map<String, Object> sosMongo = new HashMap<>();
            sosMongo.put("schoolId", schoolId);
            sosMongo.put("peopleId", parMap.get("parentTel"));
            sosMongo.put("name", parMap.get("parentName"));
            sosMongo.put("peopleType", "parent");
            sosMongo.put("processType", "sos-security");
            sosMongo.put("studentId", studentId);
            sosMongo.put("instanceId", instanceId);
            sosMongo.put("instanceInfo", instanceInfo);
            sosMongo.put("instanceVar", reVars);
            sosMongo.put("student", student);
            sosMongo.put("distance", distance);
            if ("out".equals(location)) {
                sosMongo.put("instanceYes", true);
                sosMongo.put("sosSite", "out");
            }
            saveSosInfoList.add(sosMongo);
        }

        //发送请求
        Map<String, String> par = new HashMap<>();
        par.put("data", JSONObject.toJSONString(saveSosInfoList, SerializerFeature.DisableCircularReferenceDetect));
        new Thread() {
            @Override
            public void run() {
                restTemplate.postForObject(saveProcessUrl, par, String.class);
            }
        }.start();

        return;
    }

    /**
     * 分配保安作为候选人阶段保存sos报警细节进mongodb
     *
     * @param execution
     * @param candidateIds
     */
    public void saveInstanceToMongoAtAssign(DelegateExecution execution, List<Map<String, Object>> candidateIds, String chartType, String schoolId,Object alarmInfo) {

        //保安候选任务redis - 便于对比位置以完成到达目的地任务
        Map<String, Object> redisInfo = new HashMap<>();
        String instanceId = execution.getProcessInstanceId();
        redisInfo.put("orgCode", schoolId);
        redisInfo.put("schoolId", schoolId);
        redisInfo.put("chartType", chartType);
        redisInfo.put("instanceId", instanceId);
        redisInfo.put("taskType", "candidate");
        if ("sos-security".equals(chartType)) {
            Map<String, Object> studentInfo = JSONObject.parseObject(execution.getVariable("student").toString(), Map.class);
            redisInfo.put("student", studentInfo.get("Student"));
            redisInfo.put("gps", studentInfo.get("Gps"));
            redisInfo.put("sosSign", studentInfo.get("Sos-Sign"));
        } else if ("fire-alarm".equals(chartType) || "pillar-alarm".equals(chartType)) {
            redisInfo.put("alarmInfo", alarmInfo);
        }

        //组装流程完成细节数据
//        List<Map<String, Object>> saveSosInfoList = new ArrayList<>();
//        List<Map<String, Object>> instanceInfo = new ArrayList<>();
//        String schoolId = studentInfo.get("schoolId").toString();
//        String studentId = ((Map) studentInfo.get("Student")).get("id").toString();
        for (Map<String, Object> candiOne : candidateIds) {
            String canId = candiOne.get("id").toString();
            //所有候选人存redis - node每次调redis查看自己有无报警任务 - 方便监听被安排的保安位置到报警地点没得
            jedisUtil.hset("sos_handle", "sosSecurity_" + canId + "_" + instanceId, JSONObject.toJSONString(redisInfo));

//            //存sos报警细节
//            Map<String, Object> sosMongo = new HashMap<>();
//            sosMongo.put("schoolId", schoolId);
//            sosMongo.put("peopleId", canId);
//            sosMongo.put("name", candiOne.get("name"));
//            sosMongo.put("peopleType", candiOne.get("peopleType"));
//            sosMongo.put("processType", "sos-security");
//            sosMongo.put("studentId", studentId);
//            sosMongo.put("instanceId", execution.getProcessInstanceId());
//            saveSosInfoList.add(sosMongo);

//            //流程完成进度
//            Map<String, Object> insMap = new HashMap<>();
//            insMap.put("name", candiOne.get("name"));
//            insMap.put("peopleId", canId);
//            insMap.put("peopleType", candiOne.get("peopleType"));
//            instanceInfo.add(insMap);
        }

//        Map<String, String> par = new HashMap<>();
//        par.put("people", JSONObject.toJSONString(saveSosInfoList, SerializerFeature.DisableCircularReferenceDetect));
//        par.put("instanceInfo", JSONObject.toJSONString(instanceInfo, SerializerFeature.DisableCircularReferenceDetect));
//        new Thread() {
//            @Override
//            public void run() {
//                restTemplate.postForObject(saveProcessAtAssignUrl, par, String.class);
//            }
//        }.start();

        return;
    }

    /**
     * 某个组织的队长分配任务数据存mongo
     *
     * @param execution
     * @param roleList
     */
    public void saveLeaderTaskToMongo(DelegateExecution execution, List<String> roleList) {

        //生成人物可追溯流程数据
        String schoolId = execution.getVariable("schoolId").toString();
        String instanceId = execution.getProcessInstanceId();
        List<Map<String, Object>> sosMongoList = new ArrayList<>();
        List<Map<String, Object>> insInfoList = new ArrayList<>();
        for (String role : roleList) {
            //细节
            Map<String, Object> instanceInfo = new HashMap<>();
            instanceInfo.put("name", role);
            instanceInfo.put("peopleId", role);
            insInfoList.add(instanceInfo);
            //人物
            Map<String, Object> sosMongo = new HashMap<>();
            sosMongo.put("schoolId", schoolId);
            sosMongo.put("peopleId", role);
            sosMongo.put("name", role);
            sosMongo.put("processType", "sos-security");
            sosMongo.put("instanceId", instanceId);
            sosMongoList.add(sosMongo);
        }

        Map<String, String> par = new HashMap<>();
        par.put("people", JSONObject.toJSONString(sosMongoList, SerializerFeature.DisableCircularReferenceDetect));
        par.put("instanceInfo", JSONObject.toJSONString(insInfoList, SerializerFeature.DisableCircularReferenceDetect));

        restTemplate.postForObject(savaTissueLeaderUrl, par, String.class);

    }
}
